/**
 * 随机姓名生成器类
 */
import { 
    IRandomName, 
    CustomConfig, 
    GenerateOptions,
    NameStyle, 
    NickStyle, 
    Language,
    NickNameData,
    StyledNickData
} from './types/index.js';
import { chineseNameData, chineseStyledNameData, multiLanguageNickData } from './data/index.js';
import { randomChoice, deepClone } from './utils/index.js';

/**
 * 随机姓名生成器类
 * 可以生成随机昵称、姓名等，支持多语言
 */
export class RandomName implements IRandomName {
    /** 昵称前缀数组（形容词） */
    public readonly nickHeader: string[];
    /** 昵称后缀数组（名词） */
    public readonly nickFoot: string[];
    /** 女性名字字符数组 */
    public readonly femaleNameItems: string[];
    /** 男性名字字符数组 */
    public readonly maleNameItems: string[];
    /** 单姓数组 */
    public readonly familyNameItemsSin: string[];
    /** 复姓数组 */
    public readonly familyNameItemsSur: string[];
    /** 所有名字字符数组（男女通用） */
    public readonly allName: string[];
    /** 所有姓氏数组（单姓+复姓） */
    public readonly familyNameItemsAll: string[];

    // 风格化数据集
    /** 不同风格的姓名 */
    private readonly styledNames: Map<NameStyle, { male: string[], female: string[] }>;
    
    // 自定义数据
    /** 自定义配置 */
    private customConfig: CustomConfig;
    /** 默认数据备份 */
    private readonly defaultData: {
        nickHeader: string[];
        nickFoot: string[];
        femaleNameItems: string[];
        maleNameItems: string[];
        familyNameItemsSin: string[];
        familyNameItemsSur: string[];
    };

    /**
     * 构造函数，初始化所有数据
     * @param config - 可选的自定义配置
     */
    constructor(config?: CustomConfig) {
        // 初始化中文姓名数据
        this.femaleNameItems = [...chineseNameData.female];
        this.maleNameItems = [...chineseNameData.male];
        this.familyNameItemsSin = [...chineseNameData.familyNamesSingle];
        this.familyNameItemsSur = [...chineseNameData.familyNamesCompound];
        this.allName = this.femaleNameItems.concat(this.maleNameItems);
        this.familyNameItemsAll = this.familyNameItemsSin.concat(this.familyNameItemsSur);

        // 初始化中文默认昵称数据
        const chineseNickData = multiLanguageNickData[Language.CHINESE].default;
        this.nickHeader = [...chineseNickData.headers];
        this.nickFoot = [...chineseNickData.foots];

        // 保存默认数据
        this.defaultData = {
            nickHeader: [...this.nickHeader],
            nickFoot: [...this.nickFoot],
            femaleNameItems: [...this.femaleNameItems],
            maleNameItems: [...this.maleNameItems],
            familyNameItemsSin: [...this.familyNameItemsSin],
            familyNameItemsSur: [...this.familyNameItemsSur]
        };

        // 初始化风格化数据
        this.styledNames = this.initStyledNames();

        // 初始化自定义配置
        this.customConfig = { language: Language.CHINESE };

        // 应用自定义配置
        if (config) {
            this.addCustomData(config);
        }
    }

    /**
     * 初始化不同风格的名字
     */
    private initStyledNames(): Map<NameStyle, { male: string[], female: string[] }> {
        const map = new Map<NameStyle, { male: string[], female: string[] }>();
        
        map.set(NameStyle.TRADITIONAL, {
            male: [...chineseStyledNameData[NameStyle.TRADITIONAL].male],
            female: [...chineseStyledNameData[NameStyle.TRADITIONAL].female]
        });
        
        map.set(NameStyle.MODERN, {
            male: [...chineseStyledNameData[NameStyle.MODERN].male],
            female: [...chineseStyledNameData[NameStyle.MODERN].female]
        });
        
        map.set(NameStyle.LITERARY, {
            male: [...chineseStyledNameData[NameStyle.LITERARY].male],
            female: [...chineseStyledNameData[NameStyle.LITERARY].female]
        });
        
        map.set(NameStyle.CLASSICAL, {
            male: [...chineseStyledNameData[NameStyle.CLASSICAL].male],
            female: [...chineseStyledNameData[NameStyle.CLASSICAL].female]
        });
        
        return map;
    }

    /**
     * 获取指定语言和风格的昵称数据
     * @param language - 语言
     * @param style - 风格
     * @returns 昵称数据
     */
    private getNickData(language: Language = Language.CHINESE, style?: NickStyle): NickNameData {
        const langData = multiLanguageNickData[language];
        
        if (style && langData.styled[style]) {
            return langData.styled[style];
        }
        
        return langData.default;
    }

    /**
     * 获取随机昵称前缀
     * @param style - 昵称风格
     * @param language - 语言
     * @returns 昵称前缀
     */
    public getNickHeader(style?: NickStyle, language?: Language): string {
        const lang = language || this.customConfig.language || Language.CHINESE;
        
        if (style || lang !== Language.CHINESE) {
            const nickData = this.getNickData(lang, style);
            return randomChoice(nickData.headers);
        }
        
        // 使用自定义或默认数据（中文）
        const headers = this.customConfig.customNickHeaders && !this.customConfig.mixWithDefault 
            ? this.customConfig.customNickHeaders 
            : this.nickHeader;
        return randomChoice(headers);
    }

    /**
     * 获取随机昵称后缀
     * @param style - 昵称风格
     * @param language - 语言
     * @returns 昵称后缀
     */
    public getNickFoot(style?: NickStyle, language?: Language): string {
        const lang = language || this.customConfig.language || Language.CHINESE;
        
        if (style || lang !== Language.CHINESE) {
            const nickData = this.getNickData(lang, style);
            return randomChoice(nickData.foots);
        }
        
        // 使用自定义或默认数据（中文）
        const foots = this.customConfig.customNickFoots && !this.customConfig.mixWithDefault 
            ? this.customConfig.customNickFoots 
            : this.nickFoot;
        return randomChoice(foots);
    }

    /**
     * 生成随机昵称
     * @param style - 昵称风格
     * @param language - 语言
     * @returns 随机昵称
     */
    public getNickName(style?: NickStyle, language?: Language): string {
        return this.getNickHeader(style, language) + this.getNickFoot(style, language);
    }

    /**
     * 获取随机姓氏
     * @param sur - 是否包含复姓，默认为true
     * @returns 随机姓氏
     */
    public getFamilyName(sur: boolean = true): string {
        if (sur) {
            return randomChoice(this.familyNameItemsAll);
        } else {
            return randomChoice(this.familyNameItemsSin);
        }
    }

    /**
     * 生成随机女性姓名
     * @param sur - 是否包含复姓，默认为true
     * @param style - 姓名风格
     * @returns 随机女性姓名
     */
    public getFemaleName(sur: boolean = true, style?: NameStyle): string {
        const familyName: string = this.getFamilyName(sur);
        
        // 如果指定了风格，使用风格化名字
        if (style && this.styledNames.has(style)) {
            const styledData = this.styledNames.get(style)!;
            return familyName + randomChoice(styledData.female);
        }
        
        // 使用自定义或默认数据
        const nameItems = this.getNameItems('female');
        const r: number = Math.floor(Math.random() * 2);
        const firstName: string = randomChoice(nameItems);

        if (r === 0) {
            // 生成两个字的名字
            const secondName: string = randomChoice(nameItems);
            return familyName + firstName + secondName;
        } else {
            // 生成一个字的名字
            return familyName + firstName;
        }
    }

    /**
     * 生成随机男性姓名
     * @param sur - 是否包含复姓，默认为true
     * @param style - 姓名风格
     * @returns 随机男性姓名
     */
    public getMaleName(sur: boolean = true, style?: NameStyle): string {
        const familyName: string = this.getFamilyName(sur);
        
        // 如果指定了风格，使用风格化名字
        if (style && this.styledNames.has(style)) {
            const styledData = this.styledNames.get(style)!;
            return familyName + randomChoice(styledData.male);
        }
        
        // 使用自定义或默认数据
        const nameItems = this.getNameItems('male');
        const r: number = Math.floor(Math.random() * 2);
        const firstName: string = randomChoice(nameItems);

        if (r === 0) {
            // 生成两个字的名字
            const secondName: string = randomChoice(nameItems);
            return familyName + firstName + secondName;
        } else {
            // 生成一个字的名字
            return familyName + firstName;
        }
    }

    /**
     * 生成随机姓名（不区分性别）
     * @param sur - 是否包含复姓，默认为true
     * @param style - 姓名风格
     * @returns 随机姓名
     */
    public getName(sur: boolean = true, style?: NameStyle): string {
        const familyName: string = this.getFamilyName(sur);
        
        // 如果指定了风格，随机选择男性或女性风格化名字
        if (style && this.styledNames.has(style)) {
            const styledData = this.styledNames.get(style)!;
            const gender = Math.floor(Math.random() * 2) === 0 ? 'male' : 'female';
            const names = styledData[gender];
            return familyName + randomChoice(names);
        }
        
        // 使用自定义或默认数据
        const nameItems = this.getNameItems('all');
        const r: number = Math.floor(Math.random() * 2);
        const firstName: string = randomChoice(nameItems);

        if (r === 0) {
            // 生成两个字的名字
            const secondName: string = randomChoice(nameItems);
            return familyName + firstName + secondName;
        } else {
            // 生成一个字的名字
            return familyName + firstName;
        }
    }

    /**
     * 获取名字数据项
     * @param type - 名字类型
     * @returns 名字数组
     */
    private getNameItems(type: 'male' | 'female' | 'all'): string[] {
        if (this.customConfig.customGivenNames && !this.customConfig.mixWithDefault) {
            return this.customConfig.customGivenNames;
        }
        
        switch (type) {
            case 'male':
                return this.maleNameItems;
            case 'female':
                return this.femaleNameItems;
            case 'all':
            default:
                return this.allName;
        }
    }

    /**
     * 批量生成姓名
     * @param count - 生成数量
     * @param options - 生成选项
     * @returns 姓名数组
     */
    public generateNames(count: number, options?: GenerateOptions): string[] {
        const names: string[] = [];
        const { gender = 'mixed', sur = true, style, language } = options || {};
        
        for (let i = 0; i < count; i++) {
            let name: string;
            
            if (gender === 'mixed') {
                // 随机选择性别
                const randomGender = Math.floor(Math.random() * 2) === 0 ? 'male' : 'female';
                name = randomGender === 'male' 
                    ? this.getMaleName(sur, style) 
                    : this.getFemaleName(sur, style);
            } else if (gender === 'male') {
                name = this.getMaleName(sur, style);
            } else {
                name = this.getFemaleName(sur, style);
            }
            
            names.push(name);
        }
        
        return names;
    }

    /**
     * 批量生成昵称
     * @param count - 生成数量
     * @param style - 昵称风格
     * @param language - 语言
     * @returns 昵称数组
     */
    public generateNickNames(count: number, style?: NickStyle, language?: Language): string[] {
        const nickNames: string[] = [];
        
        for (let i = 0; i < count; i++) {
            nickNames.push(this.getNickName(style, language));
        }
        
        return nickNames;
    }

    /**
     * 添加自定义数据
     * @param config - 自定义配置
     */
    public addCustomData(config: CustomConfig): void {
        this.customConfig = { ...this.customConfig, ...config };
        
        // 如果设置了混合模式，将自定义数据与默认数据合并
        if (config.mixWithDefault) {
            if (config.customFamilyNames) {
                (this.familyNameItemsSin as any) = [...this.defaultData.familyNameItemsSin, ...config.customFamilyNames];
                (this.familyNameItemsAll as any) = [...this.defaultData.familyNameItemsSin, ...this.defaultData.familyNameItemsSur, ...config.customFamilyNames];
            }
            
            if (config.customGivenNames) {
                (this.femaleNameItems as any) = [...this.defaultData.femaleNameItems, ...config.customGivenNames];
                (this.maleNameItems as any) = [...this.defaultData.maleNameItems, ...config.customGivenNames];
                (this.allName as any) = [...this.defaultData.femaleNameItems, ...this.defaultData.maleNameItems, ...config.customGivenNames];
            }
            
            if (config.customNickHeaders) {
                (this.nickHeader as any) = [...this.defaultData.nickHeader, ...config.customNickHeaders];
            }
            
            if (config.customNickFoots) {
                (this.nickFoot as any) = [...this.defaultData.nickFoot, ...config.customNickFoots];
            }
        }
    }

    /**
     * 重置为默认数据
     */
    public resetToDefault(): void {
        this.customConfig = { language: Language.CHINESE };
        
        // 恢复默认数据
        (this.nickHeader as any) = [...this.defaultData.nickHeader];
        (this.nickFoot as any) = [...this.defaultData.nickFoot];
        (this.femaleNameItems as any) = [...this.defaultData.femaleNameItems];
        (this.maleNameItems as any) = [...this.defaultData.maleNameItems];
        (this.familyNameItemsSin as any) = [...this.defaultData.familyNameItemsSin];
        (this.familyNameItemsSur as any) = [...this.defaultData.familyNameItemsSur];
        (this.allName as any) = this.femaleNameItems.concat(this.maleNameItems);
        (this.familyNameItemsAll as any) = this.familyNameItemsSin.concat(this.familyNameItemsSur);
    }

    /**
     * 获取当前配置信息
     * @returns 配置信息
     */
    public getConfig(): CustomConfig {
        return deepClone(this.customConfig);
    }

    /**
     * 获取可用的风格和语言列表
     * @returns 风格和语言信息
     */
    public getAvailableOptions(): { nameStyles: NameStyle[], nickStyles: NickStyle[], languages: Language[] } {
        return {
            nameStyles: Object.values(NameStyle),
            nickStyles: Object.values(NickStyle),
            languages: Object.values(Language)
        };
    }
}
